package com.csw.compose.ui.module.animation

import androidx.compose.animation.animateColor
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateIntOffsetAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.layout
import androidx.compose.ui.text.style.TextMotion
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.csw.compose.theme.pagePadding
import com.csw.compose.ui.Destination
import com.csw.compose.ui.components.BodyText
import com.csw.compose.ui.components.LabelText
import com.csw.compose.ui.components.LargeSpacer
import com.csw.compose.ui.components.NormalSpacer
import com.csw.compose.ui.components.OlItem
import com.csw.compose.ui.components.PrimaryTitle
import com.csw.compose.ui.components.UlItem
import com.csw.compose.ui.module.BasePage

@Preview(heightDp = 2000)
@Composable
fun ComponentAnimationPagePreview() {
    BasePage({}, "组件动画") {
        ComponentAnimationPage()
    }
}

class ComponentAnimationPageData {
    companion object : Destination("ComponentAnimationPage")
}

@Composable
fun ComponentAnimationPage() {
    Column(
        modifier = Modifier
            .padding(horizontal = pagePadding)
            .verticalScroll(rememberScrollState())
    ) {
        PrimaryTitle("简介")
        BodyText("让UI上的组件动起来")
        LabelText("众所周知compose组件需要经过组合、布局、绘制三个过程才能呈现到屏幕上，所以一个动画实现过程需要的步骤越少则对性能要求越低，效果更流畅")
        LabelText("Modifier有三个方法：layout布局子组件、graphicsLayer绘制变换、drawBehind绘制内容。通过这些方法实现动画可以减少计算量，提高流畅度")
        LargeSpacer()

        val startColor = Color.Green
        val endColor = Color.Blue
        var targetColor by remember { mutableStateOf(startColor) }
        val animateBackgroundColor by animateColorAsState(
            targetColor,
            animationSpec = tween(durationMillis = 1000),
            label = "animationBackgroundColor",
        ) {
            targetColor = if (it == startColor) {
                endColor
            } else {
                startColor
            }
        }
        LaunchedEffect(Unit) { targetColor = endColor }
        Row {
            Box(
                Modifier
                    .size(60.dp)
                    .background(animateBackgroundColor)
            )
            Text(
                "注意：修改background属性实现动画会导致重组，性能较低",
                color = MaterialTheme.colorScheme.error
            )
        }
        UlItem("animate***AsState")
        LabelText("动画的基础是Animatable通过animateTo实现数值变化")
        LabelText("compose动画库提供了很多创建数值动画的方法")
        OlItem(1, "animateValueAsState")
        LabelText("最基础的动画，内部通过Animatable实现动画，基于此又衍生出以下的数值动画")
        BodyText("一维数值")
        OlItem(1, "animateFloatAsState")
        LabelText("浮点动画")
        OlItem(2, "animateIntAsState")
        LabelText("整型动画")
        OlItem(3, "animateDpAsState")
        LabelText("DP数值动画")
        BodyText("二维数值")
        OlItem(1, "animateSizeAsState")
        LabelText("尺寸动画（宽，高）浮点型")
        OlItem(2, "animateIntSizeAsState")
        LabelText("尺寸动画（宽，高）整型")
        OlItem(3, "animateOffsetAsState")
        LabelText("偏移量动画（x，y）浮点型")
        OlItem(4, "animateIntOffsetAsState")
        LabelText("偏移量动画（x，y）整型")
        BodyText("四维数值")
        OlItem(1, "animateRectAsState")
        LabelText("矩形动画（左，上，右，下）浮点型")
        OlItem(2, "animateColorAsState")
        LabelText("颜色动画（红，绿，蓝，透明度）")

        LargeSpacer()
        val infiniteColorTransition = rememberInfiniteTransition("infiniteColorTransition")
        val infiniteBackgroundColor by infiniteColorTransition.animateColor(
            startColor, endColor, infiniteRepeatable(
                tween(durationMillis = 1000),
                repeatMode = RepeatMode.Reverse
            ), "infiniteBackgroundColor"
        )
        Row {
            Box(
                Modifier
                    .size(60.dp)
                    .drawBehind {
                        drawRect(infiniteBackgroundColor)
                    }
            )
            Text(
                "通过drawBehind实现背景绘制不会导致频繁重组",
                color = MaterialTheme.colorScheme.error
            )
        }
        UlItem("rememberInfiniteTransition")
        LabelText("创建无限动画，可以指定重复模式")
        OlItem(1, "animateValue")
        LabelText("最基础的动画方法，基于它衍生以下的方法用于快速创建数值动画")
        OlItem(2, "animateColor")
        LabelText("创建在两个颜色之间转换的动画")
        OlItem(3, "animateFloat")
        LabelText("创建在两个浮点值之间转换的动画")

        LargeSpacer()
        var size by remember { mutableStateOf(60.dp) }
        Box(
            Modifier
                .animateContentSize()
                .size(size)
                .background(startColor)
                .clickable {
                    size = if (size == 60.dp) {
                        120.dp
                    } else {
                        60.dp
                    }
                }
        ) {
            Text("点击改变尺寸")
        }
        UlItem("animateContentSize")
        LabelText("在尺寸发生改变时，以动画形式过渡（这个方法需要在尺寸设置之前调用）")

        LargeSpacer()
        Row {
            Box(
                Modifier
                    .size(60.dp)
                    .background(startColor)
            )
            val startOffset = IntOffset.Zero
            val endOffset = IntOffset(60, 60)
            var targetOffset by remember { mutableStateOf(startOffset) }
            val offsetState by animateIntOffsetAsState(targetOffset)
            Box(
                Modifier
                    .layout { measurable, constraints ->
                        val placeable = measurable.measure(constraints)
                        layout(placeable.width + offsetState.x, placeable.height + offsetState.y) {
                            placeable.placeRelative(offsetState.x, offsetState.y)
                        }
                    }
                    .size(60.dp)
                    .background(endColor)
                    .clickable {
                        targetOffset = if (targetOffset == startOffset) {
                            endOffset
                        } else {
                            startOffset
                        }
                    }
            ) {
                Text("点击偏移", color = Color.White)
            }
            Box(
                Modifier
                    .size(60.dp)
                    .background(startColor)
            )
        }
        UlItem("通过layout改变组件偏移量")
        LabelText("layout影响当前组件的大小，进而反馈给Row组件实现布局位置调整。直接修改offset属性只是绘制位置发生变化")

        LargeSpacer()
        var elevation by remember { mutableStateOf(10.dp) }
        val elevationState = animateDpAsState(elevation)
        Box(
            Modifier
                .size(60.dp)
                .graphicsLayer {
                    shadowElevation = elevationState.value.toPx()
                }
                .background(startColor)
                .pointerInput(Unit) {
                    this.detectTapGestures(
                        onPress = {
                            elevation = 0.dp
                        },
                        onTap = {
                            elevation = 10.dp
                        }
                    )
                }
        )
        NormalSpacer()
        UlItem("通过graphicsLayer改变组件悬浮高度")
        LabelText("shadow属性修改组件阴影会带来频繁重组，性能较低。这里通过graphicsLayer修改阴影，实现带有“浮力”的按钮")

        LargeSpacer()
        val scaleInfiniteTransition = rememberInfiniteTransition("scaleInfiniteTransition")
        val scaleState = scaleInfiniteTransition.animateFloat(
            1f,
            8f,
            infiniteRepeatable(
                tween(1000),
                repeatMode = RepeatMode.Reverse
            )
        )
        Box(
            Modifier
                .fillMaxWidth()
                .height(150.dp), contentAlignment = Alignment.Center
        ) {
            Text(
                "Hello",
                Modifier.graphicsLayer {
                    scaleX = scaleState.value
                    scaleY = scaleState.value
                },
                style = LocalTextStyle.current.copy(textMotion = TextMotion.Animated)
            )
        }
        UlItem("TextMotion.Animated")
        LabelText("文本动画（缩放、平移、旋转）需要设置样式为动画类型，可以优化性能")

    }

}